import Base from "src/shape/Base"
import PPTFrame from "./PPTFrame"
import { Option } from "src/shape/Scene"
import TWEEN, { Tween } from "@tweenjs/tween.js"
import { animateType } from "src/types/drawBoard"
import { Props } from "src/types/shape"

export default class {
  tabs: PPTFrame[] = []
  shapes: Miao[] = []
  tabIndex: number = 0
  curIndex: number = 0
  canvas: HTMLCanvasElement
  width: number = 800
  height: number = 600
  ctx!: CanvasRenderingContext2D | null
  canvasPre: HTMLCanvasElement
  constructor(canvas: HTMLCanvasElement, option?: Option) {
    if (option) {
      this.width = option.width || 300
      this.height = option.height || 250
    }
    this.canvas = canvas
    this.canvas.width = this.width
    this.canvas.height = this.height
    this.canvasPre = document.createElement('canvas')
    this.canvasPre.width = this.width
    this.canvasPre.height = this.height
    this.canvasPre.id = 'bagua'
    this.ctx = this.canvasPre.getContext('2d')
    this.init()
    this.animate()
  }
  addTab() {
    this.tabs.push(new PPTFrame(this.canvas, { width: this.width, height: this.height }))
  }
  removeTabByIndex(index: number) {
    this.tabs.splice(index, 1)
  }
  init() {
    const json = `{"width":800,"height":500,"shapes":[{"id":"106-32-184-255","type":"other","props":{"id":"106-32-184-255","width":0,"height":0,"x":0,"y":0,"bgcolor":"black","borderWidth":1,"borderColor":"black","fontSize":"12px","textColor":"black","text":"","scaleX":1,"scaleY":1,"rotation":0,"size":10,"textList":[],"lineHeight":0,"lineWidth":0,"lateX":0,"lateY":0,"radius":5,"isGroup":false,"shapes":[]}},{"id":"49-14-22-255","type":"Rect","props":{"id":"49-14-22-255","width":100,"height":200,"x":200,"y":200,"bgcolor":"black","borderWidth":1,"borderColor":"black","fontSize":"12px","textColor":"black","text":"","scaleX":1,"scaleY":1,"rotation":0,"size":10,"textList":[],"lineHeight":0,"lineWidth":0,"lateX":0,"lateY":0,"radius":5,"isGroup":false,"shapes":[]}},{"id":"74-94-161-255","type":"Triangle","props":{"id":"74-94-161-255","width":200,"height":200,"x":200,"y":300,"bgcolor":"black","borderWidth":1,"borderColor":"black","fontSize":"12px","textColor":"black","text":"","scaleX":1,"scaleY":1,"rotation":0,"size":10,"textList":[],"lineHeight":0,"lineWidth":0,"lateX":0,"lateY":0,"radius":5,"isGroup":false,"shapes":[]}},{"id":"53-156-19-255","type":"Arrow","props":{"id":"53-156-19-255","width":200,"height":50,"x":200,"y":400,"bgcolor":"black","borderWidth":1,"borderColor":"black","fontSize":"12px","textColor":"black","text":"","scaleX":1,"scaleY":1,"rotation":0,"size":10,"textList":[],"lineHeight":0,"lineWidth":0,"lateX":0,"lateY":0,"radius":5,"isGroup":false,"shapes":[]}},{"id":"152-97-149-255","type":"Arc","props":{"id":"152-97-149-255","width":100,"height":100,"x":400,"y":400,"bgcolor":"black","borderWidth":1,"borderColor":"black","fontSize":"12px","textColor":"black","text":"","scaleX":1,"scaleY":1,"rotation":0,"size":10,"textList":[],"lineHeight":0,"lineWidth":0,"lateX":0,"lateY":0,"radius":50,"isGroup":false,"shapes":[]}},{"id":"242-39-91-255","type":"Pentagram","props":{"id":"242-39-91-255","width":100,"height":100,"x":500,"y":500,"bgcolor":"black","borderWidth":1,"borderColor":"black","fontSize":"12px","textColor":"black","text":"","scaleX":1,"scaleY":1,"rotation":0,"size":10,"textList":[],"lineHeight":0,"lineWidth":0,"lateX":0,"lateY":0,"radius":50,"isGroup":false,"shapes":[]}},{"id":"149-210-110-255","type":"Group","props":{"id":"149-210-110-255","width":300,"height":300,"x":450,"y":200,"bgcolor":"black","borderWidth":1,"borderColor":"black","fontSize":"12px","textColor":"black","text":"","scaleX":1,"scaleY":1,"rotation":0,"size":10,"textList":[],"lineHeight":0,"lineWidth":0,"lateX":0,"lateY":0,"radius":5,"isGroup":false,"shapes":[{"id":"136-92-110-255","listeners":{},"type":"Arrow","props":{"id":"136-92-110-255","width":200,"height":50,"x":250,"y":100,"bgcolor":"red","borderWidth":1,"borderColor":"black","fontSize":"12px","textColor":"black","text":"","scaleX":1,"scaleY":1,"rotation":0,"size":10,"textList":[],"lineHeight":0,"lineWidth":0,"lateX":0,"lateY":0,"radius":5,"isGroup":false,"shapes":[]},"actived":false},{"id":"79-53-177-255","listeners":{},"type":"Arc","props":{"id":"79-53-177-255","width":100,"height":100,"x":200,"y":200,"bgcolor":"blue","borderWidth":1,"borderColor":"black","fontSize":"12px","textColor":"black","text":"","scaleX":1,"scaleY":1,"rotation":0,"size":10,"textList":[],"lineHeight":0,"lineWidth":0,"lateX":0,"lateY":0,"radius":50,"isGroup":false,"shapes":[]},"actived":false},{"id":"182-16-190-255","listeners":{},"type":"Pentagram","props":{"id":"182-16-190-255","width":100,"height":100,"x":50,"y":50,"bgcolor":"black","borderWidth":1,"borderColor":"black","fontSize":"12px","textColor":"black","text":"","scaleX":1,"scaleY":1,"rotation":0,"size":10,"textList":[],"lineHeight":0,"lineWidth":0,"lateX":0,"lateY":0,"radius":50,"isGroup":false,"shapes":[]},"actived":false}]}}]}`

    const animateType = ['', 'louver', 'shape', 'incision', 'fade', 'push-in', 'push-aside']
    for (let i = 0; i < animateType.length; i++) {
      const frame = new PPTFrame(this.canvas, { width: this.width, height: this.height })
      frame.animateType = animateType[i] as animateType
      frame.import(JSON.parse(json))
      frame.count = i + 1

      this.tabs.push(frame)
    }
    this.preview()
  }
  preview() {
    const canvas = document.createElement('canvas')
    canvas.width = this.width
    canvas.height = this.height
    let ctx = canvas.getContext('2d')
    if (!ctx) return

    this.shapes.push(
      ...this.tabs.map(scene => new Miao(
        scene.snapshot(ctx as CanvasRenderingContext2D, canvas),
        scene.animateType
      ))
    )

    type ActionType = {
      move: Tween<Props>
      shape: Miao
    }
    const { width, height } = this
    const time = 2000
    const actions: ActionType[] = []
    let action: Tween<Props> | null = null
    for (let i = 0; i < this.shapes.length; i++) {
      const shape = this.shapes[i];
      const move = new Tween(shape.props)

      switch (shape.animateType) {
        case "":
          shape.props.y = height
          move.to({ y: 0 }, time).onStart(() => {
            shape.show = true
          })
          break
        case "smooth":
        case "fade":
          shape.props.opacity = 0
          move.to({ opacity: 1 }, time)
            .onStart(() => {
              shape.show = true
            })
          break
        case "push-in":
          shape.props.x = width
          move.to({ x: 0 }, time)
            .onUpdate((obj, elapsed) => {
              shape.props.x = obj.x
              if (i == 0) return
              this.shapes[i - 1].props.x = obj.x - width
            }).onStart(() => {
              shape.show = true
              if (i == 0) return
              this.shapes[i - 1].show = true
            })
          break
        case "push-aside":
          shape.props.y = height
          move.to({ y: 0 }, time)
            .onUpdate(obj => {
              shape.props.y = obj.y
              if (i == 0) return
              this.shapes[i - 1].props.lateY = obj.y - height
            }).onStart(() => {
              shape.show = true
              if (i == 0) return
              this.shapes[i - 1].show = true
            })
          break
        case "erase":
        case "incision":
          this.qieke(shape, move, time)
          break
        case "cut-in":
        case "louver":
          this.qiekeq1(shape, move, time)
          break
        case "shape":
          const map = { r: 0, dr: Math.sqrt(width * width + height * height) / 2 }

          shape.props.x = width / 2
          shape.props.y = height / 2

          shape.customDraw = (ctx) => {
            if (i != 0) {
              ctx.drawImage(this.shapes[i - 1].imageDate, shape.props.x - width / 2, shape.props.y - height / 2)
            }

            ctx.save()
            ctx.beginPath()
            ctx.arc(shape.props.x, shape.props.y, map.r, 0, Math.PI * 2, true)
            ctx.stroke()
            ctx.clip()
            ctx.clearRect(0, 0, width, height)
            ctx.drawImage(shape.imageDate, shape.props.x - width / 2, shape.props.y - height / 2)
            ctx.closePath()

            ctx.restore()

            return true
          }

          shape.props.opacity = 1
          move.to({ opacity: 0 }, time)
            .onStart(() => {
              shape.show = true
            }).onUpdate((obj, elapsed) => {
              shape.props.opacity = 1
              map.r = elapsed * map.dr

            })
        case "cover":
          break
      }

      if (i === 0) action = move
      actions.push({ move, shape })
    }

    actions.forEach((v, i) => {
      if (i === actions.length - 1) {
        v.move.onComplete(() => {
          console.log(this.shapes);

          actions[i - 1] && (actions[i - 1].shape.show = false)
        })
        return
      }
      v.move.onComplete(() => {
        v.shape.show = false
        actions[i - 1] && (actions[i - 1].shape.show = false)
        actions[i + 1].move.start()
        // setTimeout(() => {
        //   v.shape.show = false
        //   actions[i + 1].move.start()
        // }, 1000)

      })
    })
    action && action.start()
  }
  qieke(shape: Miao, move: Tween<Props>, time: number) {
    const len = 2
    const w = this.width / len

    const distance = this.width / 2
    const arr: { x: number, y: number, w: number, h: number, dx: number, dy: number, dw: number, dh: number, lateX: number, lateY: number, lateW: number, lateH: number }[] = []
    for (let k = 0; k < len; k++) {
      arr.push({
        x: w * k + shape.props.x, y: 0,
        w, h: this.height,
        dx: w * k, dy: 0,
        dw: w, dh: this.height,
        lateX: w * k + shape.props.x, lateY: 0,
        lateW: w, lateH: this.height
      })
    }
    shape.customDraw = (ctx) => {
      for (let j = 0; j < len; j++) {
        const obj = arr[j]
        ctx.drawImage(
          shape.imageDate,
          obj.dx, obj.dy, obj.dw, obj.dh,
          obj.x, obj.y, obj.w, obj.h
        )
      }
      return true
    }

    shape.props.opacity = 1
    move.to({ opacity: 0 }, time / 2).onStart(() => {
      shape.show = true
    }).onUpdate((obj, elapsed) => {
      shape.props.opacity = 1

      for (let q = 0; q < arr.length; q++) {
        if (q < arr.length / 2) {
          arr[q].x = -distance * elapsed + arr[q].lateX
        } else {
          arr[q].x = distance * elapsed + arr[q].lateX
        }
      }
    })
  }
  qiekeq1(shape: Miao, move: Tween<Props>, time: number) {
    const len = 50
    const w = this.width / len

    const arr: { x: number, y: number, w: number, h: number, dx: number, dy: number, dw: number, dh: number, lateX: number, lateY: number, lateW: number, lateH: number }[] = []
    for (let k = 0; k < len; k++) {
      arr.push({ x: w * k, y: 0, w, h: this.height, dx: w * k, dy: 0, dw: w, dh: this.height, lateX: w * k, lateY: 0, lateW: w, lateH: this.height })
    }
    shape.customDraw = (ctx) => {
      for (let j = 0; j < len; j++) {
        const obj = arr[j]
        ctx.drawImage(
          shape.imageDate,
          obj.dx, obj.dy, obj.dw, obj.dh,
          obj.x, obj.y, obj.w, obj.h
        )
      }
      return true
    }

    shape.props.opacity = 1
    move.to({ opacity: 0 }, time / 2).onStart(() => {
      shape.show = true
    }).onUpdate((obj, elapsed) => {
      shape.props.opacity = 1
      for (let q = 0; q < arr.length; q++) {
        arr[q].w = arr[q].lateW - arr[q].lateW * elapsed
        // arr[q].h = arr[q].lateH - arr[q].lateH * elapsed
      }
    })
  }
  render() {
    if (!this.ctx) return
    this.ctx.clearRect(0, 0, this.width, this.height)

    for (let i = this.shapes.length - 1; i >= 0; i--) {
      this.shapes[i].draw(this.ctx, this.ctx as unknown as OffscreenCanvasRenderingContext2D)
    }
  }
  animate() {
    TWEEN.update()
    this.render()
    window.requestAnimationFrame(this.animate.bind(this))
  }
  // canvas-dom对象
  get domElement() {
    return this.canvas
  }
}

class Miao extends Base {
  animateType: animateType = ''
  imageDate: HTMLImageElement
  show: boolean = false
  constructor(imageDate: HTMLImageElement, type: animateType) {
    super()
    this.animateType = type
    this.imageDate = imageDate
  }
  customDraw(ctx: CanvasRenderingContext2D): boolean {
    return false
  }
  draw(ctx: CanvasRenderingContext2D, osCtx: OffscreenCanvasRenderingContext2D): void {
    if (!this.show) return
    const { x, y } = this.props

    ctx.save()
    this.transform(ctx)
    this.initOptions(ctx, 1)

    // 自定义渲染
    this.customDraw(ctx) || ctx.drawImage(this.imageDate, x, y)

    ctx.restore()
  }
}